import tkinter as tk
from tkinter import  filedialog, messagebox
from datetime import datetime
from PIL import Image, ImageTk
from tkcalendar import DateEntry

window = tk.Tk()
window.title("To Do List")
window.geometry("800x600")

columns = ["To_Do", "In Progress", "Done"]
frames = {}
cards = []
for col in columns:
    frame = tk.Frame(window, relief=tk.RAISED, borderwidth=1)
    frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
    frames[col] = frame
    label = tk.Label(frame, text=col, bg='lightblue', font=('Arial', 12, 'bold'))
    label.pack(fill=tk.X)

def add_task(task_name, priority, due_date, image_path, dialog):
    try:
        if not task_name or not priority or not due_date:
            raise ValueError("you must enter all")
        datetime.strptime(due_date, '%Y-%m-%d')  
        create_card(frames["To_Do"], task_name, priority, due_date, image_path)
        dialog.destroy()
    except ValueError as ve:
        messagebox.showerror("error", str(ve))
    except Exception as e:
        messagebox.showerror("unknown error", str(e))

def create_card_dialog():
    dialog = tk.Toplevel(window)
    dialog.title("Create New Task")
    dialog.geometry("400x300")
    
    task_name_var = tk.StringVar()
    priority_var = tk.StringVar(value="High")
    due_date_var = tk.StringVar()
    image_path_var = tk.StringVar()

    task_name_label = tk.Label(dialog, text="Task Name:")
    task_name_label.pack(pady=5)
    task_name_entry = tk.Entry(dialog, textvariable=task_name_var)
    task_name_entry.pack(pady=5)
    
    priority_label = tk.Label(dialog, text="Priority:")
    priority_label.pack(pady=5)
    priority_options = ["High", "Medium", "Low"]
    priority_menu = tk.OptionMenu(dialog, priority_var, *priority_options)
    priority_menu.pack(pady=5)
    
    due_date_label = tk.Label(dialog, text="Due Date:")
    due_date_label.pack(pady=5)
    due_date_entry = DateEntry(dialog, textvariable=due_date_var, date_pattern='yyyy-mm-dd')
    due_date_entry.pack(pady=5)
    
    def select_image():
        try:
            filename = filedialog.askopenfilename(title="Select Image", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.gif")])
            if filename:
                image_path_var.set(filename)
        except Exception as e:
            messagebox.showerror("wrongly select picture", str(e))

    confirm_button = tk.Button(dialog, text="Confirm", command=lambda: add_task(task_name_var.get(), priority_var.get(), due_date_entry.get_date().strftime('%Y-%m-%d'), image_path_var.get(), dialog))
    confirm_button.pack(pady=10)
    select_image_button = tk.Button(dialog, text="Select Image", command=select_image)
    select_image_button.pack(pady=5)

def create_card(frame, task_name, priority, due_date, image_path):
    card_frame = tk.Frame(frame, relief=tk.RAISED, borderwidth=1, padx=10, pady=10)
    
    # 绑定拖动事件
    card_frame.bind("<Button-1>", lambda event, frame=card_frame: on_press(event, frame))
    card_frame.bind("<B1-Motion>", lambda event, frame=card_frame: on_drag(event, frame))
    card_frame.bind("<ButtonRelease-1>", lambda event, frame=card_frame: on_release(event, frame))
    
    card_frame.pack(fill=tk.X, pady=5)
    
    # 保存卡片信息以便后续操作（如拖动后恢复原位置）
    card_info = {'frame': card_frame, 'original_frame': frame}
    cards.append(card_info)
    
    task_label = tk.Label(card_frame, text=f"Task: {task_name}", anchor='w')
    task_label.pack(fill=tk.X)
    priority_label = tk.Label(card_frame, text=f"Priority: {priority}", anchor='w')
    priority_label.pack(fill=tk.X)
    due_date_label = tk.Label(card_frame, text=f"Due Date: {due_date}", anchor='w')
    due_date_label.pack(fill=tk.X)
    edit_button = tk.Button(card_frame, text="Edit", command=lambda: edit_task(card_frame, task_name, priority, due_date, image_path))
    edit_button.pack(anchor='s')
    delete_button = tk.Button(card_frame, text="Delete", command=lambda: delete_card(card_frame))
    delete_button.pack(anchor='s')
    created_time_label = tk.Label(card_frame, text=f"Created: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", anchor='w')
    created_time_label.pack(fill=tk.X)
    
    if image_path:
        try:
            img = Image.open(image_path)
            img = img.resize((100, 100))
            img = ImageTk.PhotoImage(img)
            image_label = tk.Label(card_frame, image=img)
            image_label.image = img
            image_label.pack()
        except Exception as e:
            messagebox.showerror("error", str(e))
def delete_card(card_frame):
    card_frame.destroy()

def edit_task(card_frame, current_task_name, current_priority, current_due_date, current_image_path):
    edit_dialog = tk.Toplevel(window)
    edit_dialog.title("Edit Task")
    edit_dialog.geometry("400x300")
    
    task_name_var = tk.StringVar(value=current_task_name)
    priority_var = tk.StringVar(value=current_priority)
    due_date_var = tk.StringVar(value=current_due_date)
    image_path_var = tk.StringVar(value=current_image_path)

    task_name_label = tk.Label(edit_dialog, text="Task Name:")
    task_name_label.pack(pady=5)
    task_name_entry = tk.Entry(edit_dialog, textvariable=task_name_var)
    task_name_entry.pack(pady=5)
    
    priority_label = tk.Label(edit_dialog, text="Priority:")
    priority_label.pack(pady=5)
    priority_options = ["High", "Medium", "Low"]
    priority_menu = tk.OptionMenu(edit_dialog, priority_var, *priority_options)
    priority_menu.pack(pady=5)
    
    due_date_label = tk.Label(edit_dialog, text="Due Date:")
    due_date_label.pack(pady=5)
    due_date_entry = DateEntry(edit_dialog, textvariable=due_date_var, date_pattern='yyyy-mm-dd')
    due_date_entry.pack(pady=5)

    def select_image():
        try:
            filename = filedialog.askopenfilename(title="Select Image", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg;*.gif")])
            if filename:
                image_path_var.set(filename)
        except Exception as e:
            messagebox.showerror("wrongly select picture", str(e))

    confirm_button = tk.Button(edit_dialog, text="Confirm", command=lambda: save_edits(card_frame, task_name_var.get(), priority_var.get(), due_date_entry.get_date().strftime('%Y-%m-%d'), image_path_var.get(), edit_dialog))
    confirm_button.pack(pady=10)
    select_image_button = tk.Button(edit_dialog, text="Select Image", command=select_image)
    select_image_button.pack(pady=5)

def save_edits(card_frame, new_task_name, new_priority, new_due_date, new_image_path, dialog):
    try:
        for widget in card_frame.winfo_children():
            if isinstance(widget, tk.Label) and widget.cget('text').startswith("Task:"):
                widget.config(text=f"Task: {new_task_name}")
            elif isinstance(widget, tk.Label) and widget.cget('text').startswith("Priority:"):
                widget.config(text=f"Priority: {new_priority}")
            elif isinstance(widget, tk.Label) and widget.cget('text').startswith("Due Date:"):
                widget.config(text=f"Due Date: {new_due_date}")
            elif isinstance(widget, tk.Label) and hasattr(widget, 'image'):
                if new_image_path:
                    img = Image.open(new_image_path)
                    img = img.resize((100, 100))
                    img = ImageTk.PhotoImage(img)
                    widget.config(image=img)
                    widget.image = img
        dialog.destroy()
    except Exception as e:
        messagebox.showerror("wrongly edit task", str(e))

def on_press(event, card_frame):
    card_frame._drag_data = {"x": event.x, "y": event.y}
    card_frame.lift()

def on_drag(event, card_frame):
    delta_x = event.x - card_frame._drag_data["x"]
    delta_y = event.y - card_frame._drag_data["y"]
    card_frame.place(x=card_frame.winfo_x() + delta_x, y=card_frame.winfo_y() + delta_y)

def on_release(event, card_frame):
    target_widget = window.winfo_containing(event.x_root, event.y_root)
    dropped_in_frame = False
    for frame in frames.values():
        if target_widget == frame or target_widget.winfo_parent() == frame:
            drop(card_frame, frame)
            dropped_in_frame = True
            break
    if not dropped_in_frame:
        revert_to_original_frame(card_frame)

def revert_to_original_frame(card_frame):
    for card_info in cards:
        if card_info['frame'] == card_frame:
            drop(card_frame, card_info['original_frame'])
            break

def drop(card_frame, target_frame):
    card_frame.place_forget()
    for card_info in cards:
        if card_info['frame'] == card_frame:
            card_info['original_frame'] = target_frame
            break
    # 统一使用 pack 几何管理器
    card_frame.pack(in_=target_frame, fill=tk.X, pady=5)

# 假设这是您初始化卡片和绑定事件的代码
for i in range(5):
    card_frame = tk.Frame(window, width=100, height=100, borderwidth=1, relief="solid")
    card_info = {'frame': card_frame, 'original_frame': window}
    cards.append(card_info)
    
    card_frame.bind("<Button-1>", lambda event, frame=card_frame: on_press(event, frame))
    card_frame.bind("<B1-Motion>", lambda event, frame=card_frame: on_drag(event, frame))
    card_frame.bind("<ButtonRelease-1>", lambda event, frame=card_frame: on_release(event, frame))
    
    # 初始放置
    card_frame.pack(in_=window, fill=tk.X, pady=5)



button = tk.Button(window, text="Create", command = create_card_dialog)
button.pack()

window.mainloop()